﻿using System;
using System.Text;
using System.IO;
using System.Drawing;
using System.Collections.Generic;

namespace pictureViewer_consoleV
{
    class Program
    {
        static bool notExit = true;

        static void Main(string[] args)
        {
            printTest();
            Image img = Image.FromFile(@"res\1.jpg");
            Bitmap bitmap = new Bitmap(img);
            picture pic = new picture();
            pic.setbitmap(bitmap);
            pic.stretchConvert();
            Console.WriteLine(pic.toViweStr());
            pic.printColorPic();
            while (notExit)
            {
                inputWaiter(pic, img);
            }
        }

        static void printTest()
        {
            string ccc = "";
            for (int i = 0; i < pixel.lib.Length; i++)
            {
                if (i != 0) ccc += "\n";
                string temp = pixel.lib.Substring(i, 1);
                for (int j = 0; j < 100; j++)
                {
                    ccc += temp;
                }
            }
            Console.WriteLine(ccc);
            Console.WriteLine("\n\n");
        }

        static void inputWaiter(picture pic, Image img)
        {
            Console.ForegroundColor = ConsoleColor.Gray;
            Console.WriteLine("图片资源请放置于 /res 目录");
            Console.WriteLine("指令  [退出：exit] [设置缩放:scale=] [彩色：-c 图片名]");
            Console.WriteLine("请输入图片名：");
            string cmd = Console.ReadLine();
            if (cmd == "exit")
            {
                notExit = false;
                return;
            }
            bool isColorMode = false;
            string[] tempstrs;
            if (cmd.IndexOf("scale=") != -1) {
                tempstrs = cmd.Split('=');
                float cc = float.Parse(tempstrs[tempstrs.Length - 1]);
                cc = cc < 0.1f ? 0.1f: cc;
                picture.scale = cc;
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine("缩放设置成功 scale="+ cc);
                return;
            }

            if (cmd.IndexOf("-") != -1)  //附加 参数
            {
                tempstrs = cmd.Split(' ');
                if (tempstrs != null && tempstrs.Length >= 2) {
                    string g = tempstrs[0].Substring(1);
                    if (!string.IsNullOrEmpty(g)) {
                        if(g == "c") isColorMode = true;
                    }
                    cmd = tempstrs[tempstrs.Length - 1];
                }
            }

            string path = @"res\" + cmd;
            if (!File.Exists(path))
            {
                Console.WriteLine("未找到该文件！！！");
                return;
            }

            img = Image.FromFile(path);
            if (img == null) return;
            Bitmap bitmap = new Bitmap(img);
            pic.setbitmap(bitmap);
            pic.stretchConvert();
            if (isColorMode)
            {
                pic.printColorPic();
            }
            else {
                Console.WriteLine(pic.toViweStr());
            }
        }
    }
}




class pixel
{
    public static readonly uint Maxlight = 255 * 3; //最大亮度值
    public static readonly string lib = ".。∶＂∵∷十︾◎※∏╋】★▲▄〓▆█";
    public static readonly string Colorlib = "︾◎※∏╋】★▲▄〓▆█";
    public static string getPixelChar(uint lightNum,bool isColor=false)
    {
        string templib = isColor ? Colorlib : lib;

        if (templib.Length < 1) return "";
        string result = templib.Substring(0, 1);
        if (lightNum < 0) return result;
        if (lightNum < 0) return templib.Substring(templib.Length - 1, 1);

        int idx = templib.Length * (int)lightNum / (int)Maxlight;
        idx = idx < 0 ? 0 : idx;
        idx = idx > templib.Length - 1 ? templib.Length - 1 : idx;
        result = templib.Substring(idx, 1);
        return result;
    }

    public static ConsoleColor getConsColor(bool HasR, bool HasG, bool HasB, bool isLowerLum)
    {
        if (HasR && HasG && HasB)
        {
            return isLowerLum ? ConsoleColor.Gray : ConsoleColor.White;
        }
        if (HasR && HasG)
        {
            return isLowerLum ? ConsoleColor.DarkYellow : ConsoleColor.Yellow;
        }
        if (HasR && HasB)
        {
            return isLowerLum ? ConsoleColor.DarkMagenta : ConsoleColor.Magenta;
        }
        if (HasG && HasB)
        {
            return isLowerLum ? ConsoleColor.DarkCyan : ConsoleColor.Cyan;
        }
        if (HasR)
        {
            return isLowerLum ? ConsoleColor.DarkRed : ConsoleColor.Red;
        }
        if (HasG)
        {
            return isLowerLum ? ConsoleColor.DarkGreen : ConsoleColor.Green;
        }
        if (HasB)
        {
            return isLowerLum ? ConsoleColor.DarkBlue : ConsoleColor.Blue;
        }

        return ConsoleColor.Gray;
    }
}

class picture
{
    public static float scale = 1f;
    private uint maxW = 200;
    private uint maxH = 150;
    //private uint maxW = 420;
    //private uint maxH = 600;
    public uint w;
    public uint h;
    private string[,] lumData;  //灰度缓存
    private ConsoleColor[,] ColorData; //色彩缓冲
    private Bitmap bitmap;
    public picture()
    {
        setW_H(maxW, maxH);
    }

    private void setW_H(uint w, uint h)
    {
        this.w = w;
        this.h = h;
        lumData = new string[h, w];
        ColorData = new ConsoleColor[h, w];
    }

    public void setbitmap(Bitmap bitmap)
    {
        float tmaxW = (float)maxW * scale;
        float tmaxH = (float)maxH * scale;

        //等比压缩宽高
        uint tw = (uint)bitmap.Width > (uint)tmaxW ? (uint)tmaxW : (uint)bitmap.Width;
        uint cth = tw * (uint)bitmap.Height / (uint)bitmap.Width;
        uint th = cth > (uint)tmaxH ? (uint)tmaxH : cth;
        tw = th * tw / cth;

        setW_H(tw, th);
        this.bitmap = bitmap;
    }

    public void stretchConvert()
    {
        if (bitmap == null) return;
        for (int i = 0; i < h; i++)
        {
            for (int j = 0; j < w; j++)
            {
                int th = i * bitmap.Height / (int)h;
                int tw = j * bitmap.Width / (int)w;

                Color col = bitmap.GetPixel(tw, th);
                uint templum = 0;
                templum += col.R;
                templum += col.G;
                templum += col.B;
                lumData[i, j] = pixel.getPixelChar(templum,true);
                ColorData[i, j] = CaluColor(col.R, col.G, col.B);
            }
        }
    }

    public void directConvert()
    {
        if (bitmap == null) return;
        uint tw = bitmap.Width > w ? w : (uint)bitmap.Width;
        uint th = bitmap.Height > h ? h : (uint)bitmap.Height;
        for (int i = 0; i < th; i++)
        {
            for (int j = 0; j < tw; j++)
            {
                Color col = bitmap.GetPixel(j, i);
                uint templum = 0;
                templum += col.R;
                templum += col.G;
                templum += col.B;
                lumData[i, j] = pixel.getPixelChar(templum);
            }
        }
    }


    public void printColorPic() {
        for (int i = 0; i < h; i++)
        {
            Console.Write("\n");
            for (int j = 0; j < w; j++)
            {
                Console.ForegroundColor = ColorData[i, j];
                Console.Write(lumData[i, j]);
            }
        }
        Console.WriteLine();
    }
    
    private ConsoleColor CaluColor(byte r, byte g, byte b)
    {
        float MergaProp = 1f / 3f;
        float grayProp = 1f / 20f;
        ConsoleColor result = ConsoleColor.Gray;

        bool lowerLumens = true;
        uint allLum = (uint)(r + g + b);
        if (allLum > pixel.Maxlight / 2) lowerLumens = false;
        if (r == g && g == b)
        {
            return lowerLumens ? ConsoleColor.Gray : ConsoleColor.White;
        }

        List<byte> rlist = new List<byte>();
        rlist.Add(r); rlist.Add(g); rlist.Add(b);
        rlist.Sort();
        uint baseNum = rlist[0];  //最小值
        baseNum = baseNum == 0 ? 1 : baseNum;
        bool isGray = (float)(allLum - baseNum * 3) / (float)(baseNum * 3) < grayProp;

        if (!isGray)
        {
            bool isMerga = false;
            isMerga = (float)(rlist[1] - rlist[0]) / (float)(rlist[2] - rlist[0]) > MergaProp;
            bool hasR = false, hasG = false, hasB = false;
            if (isMerga)
            {
                hasR = rlist[2] == r || rlist[1] == r;
                hasG = rlist[2] == g || rlist[1] == g;
                hasB = rlist[2] == b || rlist[1] == b;
            }
            else
            {
                hasR = rlist[2] == r;
                hasG = rlist[2] == g;
                hasB = rlist[2] == b;
            }

            result = pixel.getConsColor(hasR, hasG, hasB, lowerLumens);
        }
        else
        {
            result = lowerLumens ? ConsoleColor.Gray : ConsoleColor.White;
        }

        return result;
    }

    public string toViweStr()
    {
        StringBuilder temp = new StringBuilder();
        for (int i = 0; i < h; i++)
        {
            if (i != 0) temp.Append("\n");
            for (int j = 0; j < w; j++)
            {
                temp.Append(lumData[i, j]);
            }
        }
        return temp.ToString();
    }
}

